/**
 * This file is part of the dspace-poltman project http://www.poltman.com.
 *
 * This is free software; you can redistribute it and/or modify it under
 * the terms of DuraSpace DSpace license detailed in the LICENSE and NOTICE 
 * files at the root of the source tree and available online at
 * http://www.dspace.org/license/
 * 
 */

package com.poltman.dscentral.login;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.dspace.authenticate.AuthenticationMethod;
import org.dspace.authenticate.LDAPAuthentication;
import org.dspace.authenticate.PasswordAuthentication;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.core.Context;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zkplus.spring.SpringUtil;
import org.zkoss.zul.Groupbox;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;

import com.poltman.dscentral.core.CoreSessionData;
import com.poltman.dscentral.db.entity.dspace.EPersonEntity;
import com.poltman.dscentral.db.entity.pm.BaseUserEntity;
import com.poltman.dscentral.db.service.dspace.EPersonService;
import com.poltman.dscentral.db.service.pm.BaseUserService;
import com.poltman.dscentral.db.service.pm.MainMenuGroupsService;
import com.poltman.dscentral.enums.AuthenticationMethods;

/**
 * 
 * @author Zbigniew Ciok; z.ciok@poltman.com
 * @version $Revision: 1772 $
 * 
 * @param <Groupbox>
 *
 */
public class LoginWinComposer extends SelectorComposer<Groupbox> {

	private static final long serialVersionUID = 8210889335641014220L;

	private static Logger log = Logger.getLogger(LoginWinComposer.class);
	
	@Wire
	Textbox nameTxb;
	
	@Wire
	Textbox passwordTxb;	
	
	@Listen("onClick = #confirmBtn")
	public void confirm() {
		Integer status = null;
		String email = nameTxb.getValue();
		String password = passwordTxb.getValue();

		Context context = (Context) SpringUtil.getBean("context");
		
		// Uncomment it if you want to use standard dspace authentication mechanism 
		// and comment dscentral mechanism.
		// dspace authentication:
        // status = AuthenticationManager.authenticate(context, email, password, null, null);
		
		//dscentral authentication:
		EPersonService epersonService = (EPersonService) SpringUtil.getBean("epersonService");
		EPersonEntity epersonEntity = null;
		BaseUserEntity baseUser = null;
		try {
			epersonEntity = (EPersonEntity) epersonService.findByEmail(email);
			BaseUserService baseUserService = (BaseUserService)SpringUtil.getBean("baseUserService");
			baseUser = baseUserService.findByEpersonId(epersonEntity.getEpersonId());
		} catch (Exception e) {
			log.error("login confirm error ", e);
			Messagebox.show("Login error...", "DSCentral Error", 0,  Messagebox.ERROR);
			return;
		}
		
		//DSCentral user login
		if (baseUser != null) {
			String authMethod = null;
			try {
				authMethod = baseUser.getDscAuthenticationMethod();
			} catch (Exception e) {
				Messagebox.show("Login error...", "DSCentral Error", 0,  Messagebox.ERROR);
				return;
			}
			if (authMethod == null) {
				Messagebox.show("Unknown authentication method (01)...", "DSCentral Error", 0,  Messagebox.ERROR);
				return;
			}
			if (authMethod.equals(AuthenticationMethods.Password.toString())) {
				status = passwordAuthentication(context, email, password);
			} else if (authMethod.equals(AuthenticationMethods.LDAP.toString())) {
				String netid = email; //userId
				status = ldapAuthentication(context, netid, password, null, null);
			} else if (authMethod.equals(AuthenticationMethods.X509.toString())) {
				//TODO: X.509
			} else {
				Messagebox.show("Unknown authentication method (02)...", "DSCentral Error", 0,  Messagebox.ERROR);
				return;
			}
		//DSpace user login	
		} else {
			//not dscentral user can not log in 
			Messagebox.show("You are not DSCentral user.", "DSCentral", 0,  Messagebox.INFORMATION);
			return;
		}
        
        String message = "";
        if (status == null) {
			Messagebox.show("Unknown authentication method (03)...", "DSCentral Error", 0,  Messagebox.ERROR);
			return;
        }
        switch (status) {
        	case AuthenticationMethod.SUCCESS: 
        		message = "Login OK";
        		break;
        	case AuthenticationMethod.BAD_CREDENTIALS: 
        		message = "User exists, but credenitals don't match (or LDAP server error)";
        		break;
        	case AuthenticationMethod.CERT_REQUIRED:
        		message = "Not allowed to login this way without X.509 cert."; 
        		break;
        	case AuthenticationMethod.NO_SUCH_USER : 
        		message = "User not found using this method.";
        		break;
        	case AuthenticationMethod.BAD_ARGS: 
        		message = "User/password not appropriate for this method";
        		break;
        	default: 
        	message = "Login unknown Error";
        }        
        if (status != AuthenticationMethod.SUCCESS) {
        	Messagebox.show(message, "DSCentral Error", 0,  Messagebox.ERROR);
        } else {	
			//User allowed menu items
			try {
				Map<String, String> epersonMenuItemsMap = findEPersonMenuItems(baseUser.getEpersonId());
				CoreSessionData coreSessionData = (CoreSessionData) SpringUtil.getBean("coreSessionData");
				coreSessionData.setAttribute("epersonMenuItemsMap", epersonMenuItemsMap);	
				
				context = (Context) SpringUtil.getBean("context");
				boolean isAdmin = AuthorizeManager.isAdmin(context);
				coreSessionData.setAttribute("isAdmin", isAdmin);	
			} catch (Exception e) {
				log.error("Find EPerson Menu Items Error.", e);
				Messagebox.show("Find EPerson Menu Items Error.", "DSCentral Error", 0,  Messagebox.ERROR);
				return;
			}
        	
        	Executions.sendRedirect("/pages/main-menu/main-menu.zul");
        }	
	}
	
	/**
	 * Finds user menu items
	 * @param userId
	 * @throws Exception
	 */
	private Map<String, String> findEPersonMenuItems(Integer epersonId) throws Exception {
		MainMenuGroupsService mainMenuGroupsService = (MainMenuGroupsService) SpringUtil.getBean("mainMenuGroupsService");
		List<String> items = (List<String>) mainMenuGroupsService.findEPersonMenuItems(epersonId);
		Map<String, String> itemsMap = new HashMap<String,String>();
		for (String item : items) itemsMap.put(item, item);
		return itemsMap;
	}	

	/**
	 * 
	 * @param context
	 * @param email
	 * @param password
	 * @return
	 */
	private Integer passwordAuthentication(Context context, String email, String password) {
		Integer status = null;
        PasswordAuthentication passwordAuthentication = (PasswordAuthentication) SpringUtil.getBean("passwordAuthentication");
        try {
        	status = passwordAuthentication.authenticate(context, email, password, null, null);
        } catch (Exception e) {
        	Messagebox.show("Password authenticate error...", "DSCentral Error", 0,  Messagebox.ERROR);
        	status = null;
        }
        return status;
	}
	
	/**
	 * 
	 * @param context
	 * @param netid
	 * @param password
	 * @param realm
	 * @param request
	 * @return
	 */
	private Integer ldapAuthentication(Context context,
                            		   String netid,
                            		   String password,
                            		   String realm,
                            		   HttpServletRequest request) {
		Integer status = null;
		LDAPAuthentication ldapAuthentication = (LDAPAuthentication) SpringUtil.getBean("ldapAuthentication");
		try {
			status = ldapAuthentication.authenticate(context, netid, password, realm, request);
		} catch (Exception e) {
			Messagebox.show("LDAP authenticate error...", "DSCentral Error", 0,  Messagebox.ERROR);
			status = null;
		}
		return status;
	}
}
